package com.kaisu.blog.application.user.service.impl;

import com.kaisu.blog.application.dto.PageDTO;
import com.kaisu.blog.application.user.convert.UserApplicationConvert;
import com.kaisu.blog.application.user.dto.*;
import com.kaisu.blog.application.user.service.JWTService;
import com.kaisu.blog.application.user.service.UserService;
import com.kaisu.blog.application.user.util.UserUtil;
import com.kaisu.blog.common.exceptions.InternalException;
import com.kaisu.blog.domain.file.repository.FileRepository;
import com.kaisu.blog.domain.user.User;
import com.kaisu.blog.domain.user.command.CreateUserCommand;
import com.kaisu.blog.domain.user.command.UpdateUserCommand;
import com.kaisu.blog.domain.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author kaisu
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService, UserDetailsService {
    private final UserRepository userRepository;
    private final UserApplicationConvert userApplicationConvert;
    private final JWTService jwtService;
    private final FileRepository fileRepository;

    @Override
    public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
        return userRepository.findByAccount(account);
    }

    @Override
    public LoginDTO login(String account, String password) {
        User user = userRepository.findByAccount(account);
        if (Objects.isNull(user) || user.passwordMatches(password)) {
            throw new InternalException("用户名或密码错误！");
        }
        if (!user.isEnable()) {
            throw new InternalException("该用户已被禁用！");
        }
        return new LoginDTO(userApplicationConvert.toDTO(user), jwtService.generateToken(user.getId()));
    }

    @Override
    public void create(UserCreateDTO dto) {
        User user = User.create(new CreateUserCommand(dto.username(), dto.password(), dto.phone(), dto.email(), dto.nickname()));
        if (userRepository.checkUnique(user)) {
            throw new InternalException("用户名已存在！");
        }
        user.setAvatar(fileRepository.findById("1"));
        userRepository.save(user);
    }


    @Override
    public void update(UserUpdateDTO dto) {
        User user = UserUtil.currentUser();
        user.update(new UpdateUserCommand(dto.phone(), dto.email(), dto.nickname()));
        userRepository.save(user);
    }

    @Override
    public void updatePassword(String password, String newPassword) {
        User user = UserUtil.currentUser();
        user.updatePassword(password, newPassword);
        userRepository.save(user);
    }

    @Override
    public void updateAvatar(String fileId) {
        User user = UserUtil.currentUser();
        user.updateAvatar(fileRepository.findById(fileId));
        userRepository.save(user);
    }

    @Override
    public void resetPassword(String id, String password) {
        User user = userRepository.findById(id);
        user.resetPassword(password);
        userRepository.save(user);
    }

    @Override
    public void enable(String id) {
        User user = userRepository.findById(id);
        user.enable();
        userRepository.save(user);
    }

    @Override
    public void disable(String id) {
        User user = userRepository.findById(id);
        user.disable();
        userRepository.save(user);
    }

    @Override
    public Page<UserDTO> page(PageDTO page) {
        Page<User> userPage = userRepository.page(page.searchCondition(), page.pageRequest());
        return userPage.map(userApplicationConvert::toDTO);
    }

    @Override
    public UserDTO currentUser() {
        return userApplicationConvert.toDTO(UserUtil.currentUser());
    }

    @Override
    public void follow(String followingUserId) {
        User user = UserUtil.currentUser();
        User following = userRepository.findById(followingUserId);
        user.follow(following);
        userRepository.save(user);
        userRepository.save(following);
    }

    @Override
    public void unfollow(String followingUserId) {
        User user = UserUtil.currentUser();
        User following = userRepository.findById(followingUserId);
        user.unfollow(following);
        userRepository.save(user);
        userRepository.save(following);
    }

    @Override
    public Set<FollowDTO> followers() {
        User user = UserUtil.currentUser();
        return user.getFollowers().stream().map(follow -> new FollowDTO(userApplicationConvert.toDTO(follow.getFollower()), user.isMutual(true))).collect(Collectors.toSet());
    }


    @Override
    public Set<FollowDTO> followings(String key) {
        User user = UserUtil.currentUser();
        return user.getFollowings().stream()
                .filter(follow -> follow.getFollowing().getNickname().contains(key))
                .map(follow -> new FollowDTO(userApplicationConvert.toDTO(follow.getFollowing()), user.isMutual(false))).collect(Collectors.toSet());
    }
}
